package com.shuwen.gcdj.service.statistic;

import com.alibaba.excel.util.CollectionUtils;
import com.shuwen.gcdj.bean.conditionMonitoring.response.TDSensorCodeDataAllResp;
import com.shuwen.gcdj.bean.sysDictionary.request.SysDictionaryReq;
import com.shuwen.gcdj.bean.sysDictionary.response.SysDictionaryResp;
import com.shuwen.gcdj.bean.workingConditions.request.StatisticConditionReq;
import com.shuwen.gcdj.bean.workingConditions.response.*;
import com.shuwen.gcdj.common.api.CommonResult;
import com.shuwen.gcdj.common.constant.Constants;
import com.shuwen.gcdj.common.util.BeanHelper;
import com.shuwen.gcdj.common.util.FieldUtil;
import com.shuwen.gcdj.entity.statistics.StatisticsDevicestatus;
import com.shuwen.gcdj.entity.statistics.StatisticsOperatingmodeoperation;
import com.shuwen.gcdj.mapper.mysql.Statistic.StatisticsDeviceStatusMapper;
import com.shuwen.gcdj.mapper.mysql.Statistic.StatisticsEquipmentmechanismsensorsMapper;
import com.shuwen.gcdj.mapper.mysql.Statistic.StatisticsOperatingmodeoperationMapper;
import com.shuwen.gcdj.mapper.mysql.Statistic.StatisticsWorkingconditionsMapper;
import com.shuwen.gcdj.mapper.mysql.basics.BasicsEquipmentMapper;
import com.shuwen.gcdj.mapper.mysql.sysDictionary.SysDictionaryMapper;
import com.shuwen.gcdj.mapper.tdengine.Statistic.StatisticPlcSensorMapper;
import com.shuwen.gcdj.service.BaseService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 工况统计
 *
 * @author XYC
 */
@Service
@AllArgsConstructor
@Slf4j
public class WorkingConditionsService extends BaseService<StatisticsDeviceStatusMapper, StatisticsDevicestatus> {

    private final StatisticsDeviceStatusMapper statisticsDeviceStatusMapper;

    private final StatisticsEquipmentmechanismsensorsMapper statisticsEquipmentmechanismsensorsMapper;

    private final StatisticPlcSensorMapper statisticPlcSensorMapper;

    private final SysDictionaryMapper sysDictionaryMapper;

    private final StatisticsWorkingconditionsMapper statisticsWorkingconditionsMapper;

    private final StatisticsOperatingmodeoperationMapper statisticsOperatingmodeoperationMapper;

    private final BasicsEquipmentMapper basicsEquipmentMapper;

    @Autowired
    private final HomeService homeService;

    /**
     * 设备状态信息
     *
     * @param req
     * @return
     */
    public CommonResult<StatisticsDeviceStatusDataResp> getDeviceStatusAsync(StatisticConditionReq req) {

        //判断日期是否为空没有就获取当前日期
        LocalDateTime date = req.getTs() == null ? LocalDateTime.now() : req.getTs();
        req.setTs(date);
        StatisticsDeviceStatusResp data = statisticsDeviceStatusMapper.getResult(req);
        StatisticsDeviceStatusDataResp resp = new StatisticsDeviceStatusDataResp();
        if (data == null) {
            resp.setCumulativeStoppage(Constants.NULL_HANDLING);
            resp.setCumulativeLoadedRest(Constants.NULL_HANDLING);
            resp.setCumulativeUmulativeuntimeDuration(Constants.NULL_HANDLING);
        } else {
            BeanHelper.copyProperties(data, resp);
            resp.setCumulativeStoppage(data.getCumulativeStoppage() != null ? String.valueOf(data.getCumulativeStoppage()) : Constants.NULL_HANDLING);
            resp.setCumulativeLoadedRest(data.getCumulativeLoadedRest() != null ? String.valueOf(data.getCumulativeLoadedRest()) : Constants.NULL_HANDLING);
            resp.setCumulativeStoppage(data.getCumulativeStoppage() != null ? String.valueOf(data.getCumulativeStoppage()) : Constants.NULL_HANDLING);
        }
        //判断是否是空
        return CommonResult.success(resp);
    }

    /**
     * Plc实时数据
     *
     * @param req
     * @return
     */
    public CommonResult<List<StatisticsRealtimePlcResp>> getStatisticsOperatingmodeloadRealtime(StatisticConditionReq req) {
        if(StringUtils.isEmpty(req.getEquipmentCode())){
            return CommonResult.failed("设备不存在");
        }
        List<StatisticsRealtimePlcResp> statisticsRealtimePlcResps = new ArrayList<>();
        StatisticTDConditionResp conditionResp = new StatisticTDConditionResp();
        //req.setTs(req.getTs() == null ? LocalDateTime.now() : req.getTs());
        req.setTs(LocalDateTime.now());
        //获取该设备下的所有传感器
        List<StatisticsEquipmentMechanismSensorsResp> equipmentMechanism = statisticsEquipmentmechanismsensorsMapper.getResult(req);
        //超级表
        List<SysDictionaryResp> superTables = tdTableDataList(req);
        //plc超级表数据
        SysDictionaryResp superTable = superTables.stream().filter(x -> x.getCode().contains(Constants.GANTRY_CRANE_PLC)).findFirst().orElse(null);
        SysDictionaryReq algorithmReq = new SysDictionaryReq();
        algorithmReq.setParentCode(Constants.SENSOR_ALGORITHM);
        algorithmReq.setOperateObject(req.getEquipmentCode());
        algorithmReq.setState(Constants.SYS_DICTIONARY_STATE_VALID);
        //获取Plc算法
        List<SysDictionaryResp> algorithms = sysDictionaryMapper.getList(algorithmReq);
        if (superTable == null) {
            return CommonResult.success(statisticsRealtimePlcResps);
        }
        //取出机构中的速度，载荷，位置传感器
        List<String> positionCode = equipmentMechanism.stream().map(StatisticsEquipmentMechanismSensorsResp::getPositionSensorCode).collect(Collectors.toList());
        List<String> speeds = equipmentMechanism.stream().map(StatisticsEquipmentMechanismSensorsResp::getSpeedSensorCode).collect(Collectors.toList());
        List<String> loads = equipmentMechanism.stream().map(StatisticsEquipmentMechanismSensorsResp::getLoadSensorCode).collect(Collectors.toList());
        positionCode.addAll(speeds);
        positionCode.addAll(loads);
        //去除到null值
        positionCode = positionCode.stream().filter(x -> x != null && !x.isEmpty()).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(positionCode)) {
            return CommonResult.success(statisticsRealtimePlcResps);
        }
        SysDictionaryReq statistics = new SysDictionaryReq();
        statistics.setParentCode(Constants.SENSOR_STATISTICS);
        statistics.setState(Constants.SYS_DICTIONARY_STATE_VALID);
        List<SysDictionaryResp> datas = sysDictionaryMapper.getList(statistics);
        //首页应变传感器查询数量与间隔
        SysDictionaryResp dictionaryResp = datas.stream().filter(x -> x.getValue().equals(Constants.CONDITION_MANAGEMENT)).findFirst().orElse(new SysDictionaryResp());
        //获取查询时间间隔（秒）
        int number = dictionaryResp.getCode() != null ? Integer.parseInt(dictionaryResp.getCode()) : Constants.TIME_DIFFERENCE;
        conditionResp.setSensorCode(String.join(",",positionCode));
        conditionResp.setTableName(superTable.getCode());
        conditionResp.setStartTime(req.getTs().minusSeconds(number).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        conditionResp.setEndDateTime(req.getTs().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        conditionResp.setEqupmentCode(req.getEquipmentCode());
        TDSensorCodeDataAllResp plcMeters = statisticPlcSensorMapper.getResultA(conditionResp);
        return CommonResult.success(statisticsRealtimePlcRespList( equipmentMechanism, plcMeters
                , algorithms));
    }


    public List<StatisticsRealtimePlcResp> statisticsRealtimePlcRespList(List<StatisticsEquipmentMechanismSensorsResp> equipmentMechanism, TDSensorCodeDataAllResp plcMeters
    ,List<SysDictionaryResp> algorithms)
    {
        List<StatisticsRealtimePlcResp> statisticsRealtimePlcResps = new ArrayList<>();
        plcMeters = plcMeters==null ? new TDSensorCodeDataAllResp() : plcMeters;
        for (StatisticsEquipmentMechanismSensorsResp equipmentMechanismSensorsResp : equipmentMechanism) {
            StatisticsRealtimePlcResp statisticsRealtimePlcResp = new StatisticsRealtimePlcResp();
            //位置
            String positiondata = FieldUtil.usersBlankNum(equipmentMechanismSensorsResp.getPositionSensorCode(),TDSensorCodeDataAllResp.class,plcMeters);
            //速度
            String speedData = FieldUtil.usersBlankNum(equipmentMechanismSensorsResp.getSpeedSensorCode(),TDSensorCodeDataAllResp.class,plcMeters);
            //载荷
            String loadData = FieldUtil.usersBlankNum(equipmentMechanismSensorsResp.getLoadSensorCode(),TDSensorCodeDataAllResp.class,plcMeters);
            BigDecimal positionArithmetic =positiondata!=null ? new BigDecimal(positiondata) : BigDecimal.valueOf(0);

            if (equipmentMechanismSensorsResp.getCompute().equals(Constants.LIFTING_MECHANISM_1_COMPUTE)) {
                //计算1起升
                SysDictionaryResp dictionary = algorithms.stream().filter(x -> x.getCode().contains(Constants.LIFTING_A)).findFirst().orElse(null);
                String formula = dictionary != null ? dictionary.getRemark() : Constants.COMPUTE;
                String str = positiondata + formula;
                positionArithmetic = BigDecimal.valueOf(eval(str));
            } else if (equipmentMechanismSensorsResp.getCompute().equals(Constants.LIFTING_MECHANISM_2_COMPUTE)) {
                //计算2起升
                SysDictionaryResp dictionary = algorithms.stream().filter(x -> x.getCode().contains(Constants.LIFTING_B)).findFirst().orElse(null);
                String formula = dictionary != null ? dictionary.getRemark() : Constants.COMPUTE;
                String str = positiondata + formula;
                positionArithmetic = BigDecimal.valueOf(eval(str));
            } else if (equipmentMechanismSensorsResp.getCompute().equals(Constants.LIFTING_MECHANISM_3_COMPUTE)) {
                //计算3起升
                SysDictionaryResp dictionary = algorithms.stream().filter(x -> x.getCode().contains(Constants.LIFTING_C)).findFirst().orElse(null);
                String formula = dictionary != null ? dictionary.getRemark() : Constants.COMPUTE;
                String str = positiondata + formula;
                positionArithmetic = BigDecimal.valueOf(eval(str));
            }
            //速度公式
            SysDictionaryResp speedResp = algorithms.stream().filter(x -> x.getCode().contains(Constants.SPEED)).findFirst().orElse(null);
            String speed = speedResp != null ? speedResp.getRemark() : Constants.OUTCOME;
            String strSpeed = speedData + speed;
            //载荷公式
            SysDictionaryResp loadResp = algorithms.stream().filter(x -> x.getCode().contains(Constants.LOAD)).findFirst().orElse(null);
            String load = loadResp != null ? loadResp.getRemark() : Constants.OUTCOME;
            String strLoad = loadData + load;
            //计算速度
            BigDecimal speedArithmetic = BigDecimal.valueOf(eval(strSpeed));
            //计算载荷
            BigDecimal loadArithmetic = BigDecimal.valueOf(eval(strLoad));
            statisticsRealtimePlcResp.setEquipmentCode(equipmentMechanismSensorsResp.getEquipmentCode());
            statisticsRealtimePlcResp.setInstitution(equipmentMechanismSensorsResp.getInstitution());
            statisticsRealtimePlcResp.setPosition(positiondata!= null ? String.valueOf(positionArithmetic.setScale(2, RoundingMode.HALF_UP)) : Constants.NULL_HANDLING);
            statisticsRealtimePlcResp.setSpeed(speedData!= null ? String.valueOf(speedArithmetic.setScale(2, RoundingMode.HALF_UP)) : Constants.NULL_HANDLING);
            statisticsRealtimePlcResp.setLoad(loadData != null ? String.valueOf(loadArithmetic.setScale(2, RoundingMode.HALF_UP)) : Constants.NULL_HANDLING);
            statisticsRealtimePlcResp.setIsOnline(plcMeters.getTs()!=null);
            statisticsRealtimePlcResps.add(statisticsRealtimePlcResp);
        }
        return statisticsRealtimePlcResps;
    }


    /**
     * 累计统计
     *
     * @param req
     * @return
     */
    public CommonResult<List<StatisticsPlcCumulativeDataResp>> getStatisticsOperatingmodeloadAsync(StatisticConditionReq req) {
        if(StringUtils.isEmpty(req.getEquipmentCode())){
            return CommonResult.failed("设备不存在");
        }
        List<StatisticsPlcCumulativeDataResp> statisticsPlcCumulativeDataResps = new ArrayList<>();
        //判断日期是否为空没有就获取当前日期
        req.setTs(req.getTs() == null ? LocalDateTime.now() : req.getTs());
        //获取该设备下的所有机构
        List<StatisticsEquipmentMechanismSensorsResp> equipmentMechanism = statisticsEquipmentmechanismsensorsMapper.getResult(req);
        //所在日期的工况数据
        List<StatisticsWorkingconditionsResp> statisticsWorkingconditionsResps = statisticsWorkingconditionsMapper.setworkingconditionsMap(req);
        for (StatisticsEquipmentMechanismSensorsResp statisticsEquipmentMechanismSensorsResp : equipmentMechanism) {
            StatisticsIdleResp statisticsIdleResp = new StatisticsIdleResp();
            StatisticsPlcCumulativeDataResp statisticsPlcCumulativeDataResp = new StatisticsPlcCumulativeDataResp();
            //带载
            StatisticsWorkingconditionsResp  latestLoad = statisticsWorkingconditionsResps.stream().filter
                            (source -> source.getInstitution().equals(statisticsEquipmentMechanismSensorsResp.getInstitution()) && source.getIsloaded().equals(true))
                    .max(Comparator.comparing(StatisticsWorkingconditionsResp::getTime))
                    .orElse(new StatisticsWorkingconditionsResp());
            //空载
            StatisticsWorkingconditionsResp  latestLoadIdle = statisticsWorkingconditionsResps.stream().filter
                    (source -> source.getInstitution().equals(statisticsEquipmentMechanismSensorsResp.getInstitution()) && source.getIsloaded().equals(false))
                    .max(Comparator.comparing(StatisticsWorkingconditionsResp::getTime)).orElse(new StatisticsWorkingconditionsResp());
            //最新最大载荷
            StatisticsWorkingconditionsResp statisticsWorkingconditionsResp = statisticsWorkingconditionsResps.stream().filter
                    (source -> source.getInstitution().equals(statisticsEquipmentMechanismSensorsResp.getInstitution())&& source.getIsloaded().equals(true))
                    .max(Comparator.comparing(StatisticsWorkingconditionsResp::getTime)).orElse(new StatisticsWorkingconditionsResp());
            statisticsIdleResp.setDuration(latestLoadIdle.getDuration() == null ? Constants.NULL_HANDLING : String.valueOf(latestLoadIdle.getDuration()));
            statisticsIdleResp.setNumber(latestLoadIdle.getNumber() == null ? Constants.NULL_HANDLING : String.valueOf(latestLoadIdle.getNumber()));
            statisticsIdleResp.setMaxSpeed(latestLoadIdle.getMaxspeed() == null ? Constants.NULL_HANDLING : String.valueOf(latestLoadIdle.getMaxspeed()));
            statisticsPlcCumulativeDataResp.setEquipmentCode(req.getEquipmentCode());
            statisticsPlcCumulativeDataResp.setEvaluateObject(statisticsEquipmentMechanismSensorsResp.getInstitution());
            statisticsPlcCumulativeDataResp.setNumber(latestLoad.getNumber() == null ? Constants.NULL_HANDLING : String.valueOf(latestLoad.getNumber()));
            statisticsPlcCumulativeDataResp.setDuration(latestLoad.getDuration() == null ? Constants.NULL_HANDLING : String.valueOf(latestLoad.getDuration()));
            statisticsPlcCumulativeDataResp.setMaxSpeed(latestLoad.getMaxspeed() == null ? Constants.NULL_HANDLING : String.valueOf(latestLoad.getMaxspeed()));
            statisticsPlcCumulativeDataResp.setTime(latestLoad.getTime() == null ? req.getTs() : latestLoad.getTime());
            statisticsPlcCumulativeDataResp.setMaxLoad(statisticsWorkingconditionsResp.getMaxLoad() != null ? String.valueOf(statisticsWorkingconditionsResp.getMaxLoad()) : Constants.NULL_HANDLING);
            statisticsPlcCumulativeDataResp.setCumulativeLoad(statisticsWorkingconditionsResp.getCumulativeLoad() != null ? String.valueOf(statisticsWorkingconditionsResp.getCumulativeLoad()) : Constants.NULL_HANDLING);
            statisticsPlcCumulativeDataResp.setPlcCumulativeDataRespidles(statisticsIdleResp);
            statisticsPlcCumulativeDataResps.add(statisticsPlcCumulativeDataResp);
        }
        return CommonResult.success(statisticsPlcCumulativeDataResps);
    }


    /**
     * 热力图
     *
     * @param req
     * @return
     */
    public CommonResult<StatisticsThermalMapResp> getListOperatingmodeoperationAsync(StatisticConditionReq req) {
        if(StringUtils.isEmpty(req.getEquipmentCode())){
            return CommonResult.failed("设备不存在");
        }
        StatisticsThermalMapResp statisticsThermalMapResp = new StatisticsThermalMapResp();
        SysDictionaryReq sysDictionaryReq = new SysDictionaryReq();
        //判断日期是否为空没有就获取当前日期
        //req.setTs(req.getTs() == null ? LocalDateTime.now() : req.getTs());
        sysDictionaryReq.setParentCode(Constants.STATISTICS_OPERATINGMODEOPERATION_POSITION);
        sysDictionaryReq.setOperateObject(req.getEquipmentCode());
        sysDictionaryReq.setState(Constants.SYS_DICTIONARY_STATE_VALID);
        //获取所有位置
        List<SysDictionaryResp> sysDictionary = sysDictionaryMapper.getList(sysDictionaryReq);
        String positionCode = req.getEquipmentCode() + "_" + req.getPositionValue();
        //拿取指定位置数据
        SysDictionaryResp position = sysDictionary.stream().filter(x -> x.getCode().equals(positionCode))
                .findFirst().orElse(null);
        //获取最新热力图数据
        if (position == null) {
            return CommonResult.success(statisticsThermalMapResp);
        }
        StatisticsOperatingmodeoperation listicsOperationMap = statisticsOperatingmodeoperationMapper.getListicsOperationMap(position.getValue(), req.getEquipmentCode());
        statisticsThermalMapResp.setPosition(position.getValue());
        statisticsThermalMapResp.setPositionName(position.getName());
        statisticsThermalMapResp.setEquipmentCode(req.getEquipmentCode());
        if (listicsOperationMap == null) {
            statisticsThermalMapResp.setHeatMapDataX(new ArrayList<>());
            statisticsThermalMapResp.setHeatMapDataY(new ArrayList<>());
            return CommonResult.success(statisticsThermalMapResp);
        }
        //拿去（）中的值
        List<String> aStrings = solveUrl(listicsOperationMap.getHeatMapData());

        List<StatisticHeatMapResp> statisticHeatMaps=new ArrayList<>();
        //循环遍历取值
        for (String heat : aStrings) {
            String[] ary = heat.split(",");
            StatisticHeatMapResp statisticHeatMapResp=new StatisticHeatMapResp();
            statisticHeatMapResp.setHeatMapDataX(Integer.valueOf(ary[0]));
            statisticHeatMapResp.setHeatMapDataY(Double.valueOf(ary[1]));
            statisticHeatMaps.add(statisticHeatMapResp);
        }
        //排序
        statisticHeatMaps=statisticHeatMaps.stream().sorted(Comparator.comparing(StatisticHeatMapResp::getHeatMapDataX)).collect(Collectors.toList());
        statisticsThermalMapResp.setHeatMapDataX(statisticHeatMaps.stream().map(StatisticHeatMapResp::getHeatMapDataX).collect(Collectors.toList()));
        statisticsThermalMapResp.setHeatMapDataY(statisticHeatMaps.stream().map(StatisticHeatMapResp::getHeatMapDataY).collect(Collectors.toList()));
        statisticsThermalMapResp.setTime(listicsOperationMap.getTime());
        return CommonResult.success(statisticsThermalMapResp);
    }

    //获取td超级表名
    public List<SysDictionaryResp> tdTableDataList(StatisticConditionReq req) {
        SysDictionaryReq superTableReq = new SysDictionaryReq();
        superTableReq.setParentCode(Constants.EQUIPMENT_CODE_TDSTABLE);
        superTableReq.setOperateObject(req.getEquipmentCode());
        superTableReq.setState(Constants.SYS_DICTIONARY_STATE_VALID);
        List<SysDictionaryResp> superTables = sysDictionaryMapper.getList(superTableReq);
        return superTables;
    }


    //取出String中()中的字段
    public static List<String> solveUrl(String url) {   // 处理函数
        int i = 0;
        String pattern = "\\([^)]*\\)"; // 匹配（） 的表达式
        List<String> data = new ArrayList<String>();
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(url);
        while (m.find()) {    // 当字符串中有匹配到 {} 时
            String param = m.group(0);  // {} 和里面的内容
            String a = param.substring(1, param.length() - 1);
            data.add(a);
            i++;
        }
        return data;
    }


    /**
     * 使用java eval 计算字符串表达式
     *
     * @param str 字符串表达式
     * @return double 类型的结果
     */
    public static Double eval(String str) {

        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine se = manager.getEngineByName("js");
        Double result = null;

        try {
            result = Double.valueOf(se.eval(str).toString());
            if (result == null) {
                result = new Double(0);
            }
        } catch (ScriptException e) {
            e.printStackTrace();
        }
        return result;
    }
}
